﻿using GuitarFX_Audio;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Media.Devices;
using Windows.System.Threading;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace GuitarFX
{
    class DbToRatioConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            float ratioValue = System.Convert.ToSingle(value);

            float limit = parameter != null ? System.Convert.ToSingle(parameter) : -120f;

            float retVal = limit;
            if (ratioValue > 0.0)
            {
                retVal = (float)(20.0 * Math.Log10(ratioValue));
                if (retVal < limit)
                    retVal = limit;
            }
            return retVal;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            float dbValue = System.Convert.ToSingle(value);
            return (float)(Math.Pow(10, dbValue / 20.0));
        }
    }
    class MsToTimeSpanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return ((TimeSpan)value).TotalMilliseconds;

        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            return TimeSpan.FromMilliseconds(System.Convert.ToDouble(value));
        }
    }

    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        GuitarFX_Audio.AudioFX m_AudioFX;



        public MainPage()
        {
            this.InitializeComponent();
        }

        private async Task CreateAudioAsync()
        {
            ReleaseAudio();

            m_AudioFX = await AudioFX.CreateAsync(
                MediaDevice.GetDefaultAudioCaptureId(AudioDeviceRole.Default),
                MediaDevice.GetDefaultAudioRenderId(AudioDeviceRole.Default));
            
            SliderMasterVolume.DataContext = m_AudioFX;
            DelayFeedback.DataContext = m_AudioFX;
            DelayTime.DataContext = m_AudioFX;
        }

        private void ReleaseAudio()
        {
            SliderMasterVolume.DataContext = null;
            if (m_AudioFX != null)
            {
                m_AudioFX.Dispose();
                m_AudioFX = null;
            }
        }

        private async void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
        {
            try
            {
                if (PowerSwitch.IsOn)
                {
                    PowerLed.Fill = new SolidColorBrush(Colors.Red);

                    if (m_AudioFX == null)
                        await CreateAudioAsync();

                    if (m_AudioFX.State == AudioFXStateEnum.UnInitialized)
                        await m_AudioFX.InitializeAsync();

                    m_AudioFX.Start();

                    PowerLed.Fill = new SolidColorBrush(Colors.Green);
                }
                else
                {

                   if (m_AudioFX != null && m_AudioFX.State == AudioFXStateEnum.Started)
                        m_AudioFX.Stop();

                    PowerLed.Fill = new SolidColorBrush(Colors.DarkGray);
                }
            }
            catch (Exception ex)
            {
                ErrorText.Text = WasapiErrorToString(ex);
                PowerSwitch.IsOn = false;
            }
        }

        public const uint AUDCLNT_E_NOT_INITIALIZED = 0x88890001;
        public const uint AUDCLNT_E_ALREADY_INITIALIZED = 0x88890002;
        public const uint AUDCLNT_E_WRONG_ENDPOINT_TYPE = 0x88890003;
        public const uint AUDCLNT_E_DEVICE_INVALIDATED = 0x88890004;
        public const uint AUDCLNT_E_NOT_STOPPED = 0x88890005;
        public const uint AUDCLNT_E_BUFFER_TOO_LARGE = 0x88890006;
        public const uint AUDCLNT_E_OUT_OF_ORDER = 0x88890007;
        public const uint AUDCLNT_E_UNSUPPORTED_FORMAT = 0x88890008;
        public const uint AUDCLNT_E_INVALID_SIZE = 0x88890009;
        public const uint AUDCLNT_E_DEVICE_IN_USE = 0x8889000a;
        public const uint AUDCLNT_E_BUFFER_OPERATION_PENDING = 0x8889000b;
        public const uint AUDCLNT_E_THREAD_NOT_REGISTERED = 0x8889000c;
        public const uint AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED = 0x8889000e;
        public const uint AUDCLNT_E_ENDPOINT_CREATE_FAILED = 0x8889000f;
        public const uint AUDCLNT_E_SERVICE_NOT_RUNNING = 0x88890010;
        public const uint AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED = 0x88890011;
        public const uint AUDCLNT_E_EXCLUSIVE_MODE_ONLY = 0x88890012;
        public const uint AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL = 0x88890013;
        public const uint AUDCLNT_E_EVENTHANDLE_NOT_SET = 0x88890014;
        public const uint AUDCLNT_E_INCORRECT_BUFFER_SIZE = 0x88890015;
        public const uint AUDCLNT_E_BUFFER_SIZE_ERROR = 0x88890016;
        public const uint AUDCLNT_E_CPUUSAGE_EXCEEDED = 0x88890017;
        public const uint AUDCLNT_E_BUFFER_ERROR = 0x88890018;
        public const uint AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED = 0x88890019;
        public const uint AUDCLNT_E_INVALID_DEVICE_PERIOD = 0x88890020;
        public const uint AUDCLNT_E_INVALID_STREAM_FLAG = 0x88890021;
        public const uint AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE = 0x88890022;
        public const uint AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES = 0x88890023;
        public const uint AUDCLNT_E_OFFLOAD_MODE_ONLY = 0x88890024;
        public const uint AUDCLNT_E_NONOFFLOAD_MODE_ONLY = 0x88890025;
        public const uint AUDCLNT_E_RESOURCES_INVALIDATED = 0x88890026;
        public const uint AUDCLNT_E_RAW_MODE_UNSUPPORTED = 0x88890027;
        static string WasapiErrorToString(Exception e)
        {
            switch ((uint)e.HResult)
            {
                case AUDCLNT_E_NOT_INITIALIZED:
                    return "Audio client is not initialized";
                case AUDCLNT_E_ALREADY_INITIALIZED:
                    return "Audio client is already initialized";
                case AUDCLNT_E_DEVICE_INVALIDATED:
                    return "The audio endpoint device has been unplugged, or the audio hardware or associated hardware resources have been reconfigured, disabled, removed, or otherwise made unavailable for use.";
                    
                case AUDCLNT_E_SERVICE_NOT_RUNNING:
                    return "The Windows audio service is not running.";
                    
                case AUDCLNT_E_WRONG_ENDPOINT_TYPE:
                    return "The loopback flag is set but the endpoint device is a capture device, not a rendering device.";
                    
                case AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED:
                    return "The requested buffer size is not aligned. This code can be returned for a render or a capture device if the caller specified exclusive mode and the event callback flags.";
                    
                case AUDCLNT_E_BUFFER_SIZE_ERROR:
                    return "Indicates that the buffer duration value requested by an exclusive-mode client is out of range. The requested duration value for pull mode must not be greater than 500 milliseconds; for push mode the duration value must not be greater than 2 seconds";
                    
                case AUDCLNT_E_CPUUSAGE_EXCEEDED:
                    return "Indicates that the process-pass duration exceeded the maximum CPU usage. The audio engine keeps track of CPU usage by maintaining the number of times the process-pass duration exceeds the maximum CPU usage. The maximum CPU usage is calculated as a percent of the engine's periodicity. The percentage value is the system's CPU throttle value (within the range of 10% and 90%). If this value is not found, then the default value of 40% is used to calculate the maximum CPU usage.";
                    
                case AUDCLNT_E_DEVICE_IN_USE:
                    return "The endpoint device is already in use. Either the device is being used in exclusive mode, or the device is being used in shared mode and the caller asked to use the device in exclusive mode.";
                    
                case AUDCLNT_E_ENDPOINT_CREATE_FAILED:
                    return "The method failed to create the audio endpoint for the render or the capture device. This can occur if the audio endpoint device has been unplugged, or the audio hardware or associated hardware resources have been reconfigured, disabled, removed, or otherwise made unavailable for use.";
                    
                case AUDCLNT_E_INVALID_DEVICE_PERIOD:
                    return "The device period requested by an exclusive-mode client is greater than 500 milliseconds.";
                    
                case AUDCLNT_E_UNSUPPORTED_FORMAT:
                    return "The audio engine (shared mode) or audio endpoint device (exclusive mode) does not support the specified format.";
                    
                case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED:
                    return "The caller is requesting exclusive-mode use of the endpoint device, but the user has disabled exclusive-mode use of the device.";
                    
                case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL:
                    return "The eventcallback flag is set but parameters BufferDuration and Periodicity are not equal";
                    
                case AUDCLNT_E_NOT_STOPPED:
                    return "Audio client s not stopped";
                    
                case AUDCLNT_E_BUFFER_TOO_LARGE:
                    return "Buffer too large";
                    
                case AUDCLNT_E_OUT_OF_ORDER:
                    return "Calls out of order";
                    
                case AUDCLNT_E_INVALID_SIZE:
                    return "Invalid size";
                    
                case AUDCLNT_E_BUFFER_OPERATION_PENDING:
                    return "Buffer operation is pending";
                    
                case AUDCLNT_E_THREAD_NOT_REGISTERED:
                    return "Thread is not registered";
                    
                case AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED:
                    return "Event handle was not expected";
                    
                case AUDCLNT_E_EXCLUSIVE_MODE_ONLY:
                    return "Exclusive mode only";
                    
                case AUDCLNT_E_EVENTHANDLE_NOT_SET:
                    return "Event handle is not set";
                    
                case AUDCLNT_E_INCORRECT_BUFFER_SIZE:
                    return "Incorrect buffer size";
                    
                case AUDCLNT_E_BUFFER_ERROR:
                    return "Buffer error";
                    
                case AUDCLNT_E_INVALID_STREAM_FLAG:
                    return "Invalid stream flag";
                    
                case AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE:
                    return "Audio endpoint is not offload capable";
                    
                case AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES:
                    return "Out of offload resources";
                    
                case AUDCLNT_E_OFFLOAD_MODE_ONLY:
                    return "Offload mode only";
                    
                case AUDCLNT_E_NONOFFLOAD_MODE_ONLY:
                    return "Non-offload mode only";
                    
                case AUDCLNT_E_RESOURCES_INVALIDATED:
                    return "Resources invalidated";
                    
                case AUDCLNT_E_RAW_MODE_UNSUPPORTED:
                    return "Raw mode not supported";
                    
            }
            return e.Message;
        }
    }
}
